//
// See the file COPYING for redistribution information.
//

#ifndef __NAIPAX_CACHE_HPP__
#define __NAIPAX_CACHE_HPP__

#include <stdint.h>
#include <time.h>

namespace Naipax {
    class CacheData {
    public:
        uint32_t mKeyLen;
        uint32_t mValueLen;
        time_t mExpireTime;
        char *mpKey;
        char *mpValue;
    };
    
    /** Generic cache class
     *
     * The class maintains a fixed table for storing data. A simple
     * hash algorithm, elf hash for now, is used to generate hash keys
     * for data. When there is a collision during insertion, old data
     * will be replaced with new data.
     */
    class Cache {
    public:
        /** Constructor
         *
         * @param KeySize
         * @param ValueSize
         * @param CacheSlots The number of data slots. It would better
         *        be a prime number.
         * @exception Error::CANNOT_INIT_CACHE If the internal cache table
         *            cannot be allocated.
         */
        Cache(uint32_t KeySize, uint32_t ValueSize,
              uint32_t CacheSlots = 104729);

        /// Destructor
        ~Cache();

        /** Add data into cache
         *
         * @param pKey
         * @param KeyLen
         * @param pValue
         * @param ValueLen ValueLen can be 0.
         * @param Timeout Default value is 3600 seconds.
         * @return true When pKey and pValue are successfully inserted.
         * @return false If KeyLen exceeds KeySize;
         *         if pKey or pValue is NULL or if KeyLen is 0.
         */
        bool Set(const void *pKey, uint32_t KeyLen,
                 const void *pValue, uint32_t ValueLen,
                 time_t Timeout = 3600);

        /** Retrieve data from cache
         *
         * @param pKey
         * @param KeyLen
         * @param pValue
         * @param pValueLen If *pValueLen is zero, then the content of
         *        pValue will stay as the original.
         * @return true If there is a hit in the internal cache table.
         * @return false If KeyLen exceeds KeySize;
         *         if pKey, pValue, or pValueLen is NULL or if KeyLen is 0.
         *         Or if there is no hit.
         */
        bool Get(const void *pKey, uint32_t KeyLen,
                 void *pValue, uint32_t *pValueLen);

        /** Check if pKey lives in cache.
         *
         * @return true if there is a hit and no error occurs.
         * @return false If KeyLen exceeds KeySize;
         *         if pKey, pValue, or pValueLen is NULL or if KeyLen is 0.
         *         Or if there is no hit.
         */
        bool Has(const void *pKey, uint32_t KeyLen);

    private:
        uint32_t _mCacheSlots;
        uint32_t _mKeySize;
        uint32_t _mValueSize;
        CacheData *_mpCacheTable;
    };
};

#endif // __NAIPAX_CACHE_HPP__
